#define _GNU_SOURCE
#include "app_serial.h"
#include <termios.h>
#include <stdio.h>
/**
 * @brief 设置波特率
 * 1 声明termios 结构体
   2 通过get 方法   取出默认的结构体值
   3 对结构体值进行修改 
4 通过set方法 设置修改后的值 （暂不生效）
 */
int app_serial_baud(app_device_t *device ,SERIAL_BAUD_RATE baud_rate)
{
    // * 1 声明termios 结构体
    struct termios  termios_attr;
    // 2 通过get 方法   取出默认的结构体值
    int ret= tcgetattr(device->dev_fd,&termios_attr);
    if(ret==-1)
    {
        perror("tcgetattr fail");
        return -1;
    }

    // 3 对结构体值进行修改 
    cfsetspeed(&termios_attr,baud_rate);

    // 4 通过set方法 设置修改后的值 （暂不生效）
    ret=tcsetattr(device->dev_fd,TCSAFLUSH,&termios_attr);

    if(ret==-1)
    {
        perror("tcsetattr fail");
        return -1;
    }
    return 0;

}


/**
 * @brief 设置停止位
 * 1 声明termios 结构体
   2 通过get 方法   取出默认的结构体值
   3 对结构体值进行修改 
4 通过set方法 设置修改后的值 （暂不生效）
 */
int app_serial_stopbit(app_device_t *device ,SERIAL_STOP_BIT stopbit)
{
    // * 1 声明termios 结构体
    struct termios  termios_attr;
    // 2 通过get 方法   取出默认的结构体值
    int ret= tcgetattr(device->dev_fd,&termios_attr);
    if(ret==-1)
    {
        perror("tcgetattr fail");
        return -1;
    }

    // 3 对结构体值进行修改 
    termios_attr.c_cflag &= ~CSTOPB;  // 清除停止位
    termios_attr.c_cflag |= stopbit; // 设置停止位


    // 4 通过set方法 设置修改后的值 （暂不生效）
    ret=tcsetattr(device->dev_fd,TCSAFLUSH,&termios_attr);

    if(ret==-1)
    {
        perror("tcsetattr fail");
        return -1;
    }
    return 0;

}


/**
 * @brief 设置校验位
 * 1 声明termios 结构体
   2 通过get 方法   取出默认的结构体值
   3 对结构体值进行修改 
4 通过set方法 设置修改后的值 （暂不生效）
 */
int app_serial_parity(app_device_t *device ,SERIAL_PARITY parity)
{
    // * 1 声明termios 结构体
    struct termios  termios_attr;
    // 2 通过get 方法   取出默认的结构体值
    int ret= tcgetattr(device->dev_fd,&termios_attr);
    if(ret==-1)
    {
        perror("tcgetattr fail");
        return -1;
    }

    // 3 对结构体值进行修改 
    termios_attr.c_cflag &= ~(PARENB | PARODD); // 清除校验位、
    termios_attr.c_cflag |= parity;             // 设置校验位



    // 4 通过set方法 设置修改后的值 （暂不生效）
    ret=tcsetattr(device->dev_fd,TCSAFLUSH,&termios_attr);

    if(ret==-1)
    {
        perror("tcsetattr fail");
        return -1;
    }
    return 0;

}

/**
 * @brief 设置原始模式
 * 1 声明termios 结构体
   2 通过get 方法   取出默认的结构体值
   3 对结构体值进行修改 
4 通过set方法 设置修改后的值 （暂不生效）
 */
int app_serial_makeraw(app_device_t *device )
{
    // * 1 声明termios 结构体
    struct termios  termios_attr;
    // 2 通过get 方法   取出默认的结构体值
    int ret= tcgetattr(device->dev_fd,&termios_attr);
    if(ret==-1)
    {
        perror("tcgetattr fail");
        return -1;
    }

    // 3 对结构体值进行修改 
    cfmakeraw(&termios_attr);


    // 4 通过set方法 设置修改后的值 （暂不生效）
    ret=tcsetattr(device->dev_fd,TCSAFLUSH,&termios_attr);

    if(ret==-1)
    {
        perror("tcsetattr fail");
        return -1;
    }
    return 0;
}

/**
 * @brief 设置阻塞模式
 * @param isblock 1:阻塞模式  0:非阻塞模式
 * 1 声明termios 结构体
   2 通过get 方法   取出默认的结构体值
   3 对结构体值进行修改 
4 通过set方法 设置修改后的值 （暂不生效）
 */
int app_serial_isblock(app_device_t *device,int isblock )
{
    // * 1 声明termios 结构体
    struct termios  termios_attr;
    // 2 通过get 方法   取出默认的结构体值
    int ret= tcgetattr(device->dev_fd,&termios_attr);
    if(ret==-1)
    {
        perror("tcgetattr fail");
        return -1;
    }

    // 3 对结构体值进行修改 
    if(isblock==1)
    {
        termios_attr.c_cc[VTIME] = 0; //无限等待
        termios_attr.c_cc[VMIN] = 1;//至少一个字符

    }
    else
    {
        termios_attr.c_cc[VTIME] = 2;//等待100毫秒
        termios_attr.c_cc[VMIN] = 0; //无数据也可以返回
    }

    // 4 通过set方法 设置修改后的值 （暂不生效）
    ret=tcsetattr(device->dev_fd,TCSAFLUSH,&termios_attr);

    if(ret==-1)
    {
        perror("tcsetattr fail");
        return -1;
    }
    return 0;
}


/**
 * @brief 对设备进行串口设置
 */
int app_serial_init(app_device_t *device)
{
   //1 设置波特率
   int ret= app_serial_baud(device,BR_115200);
   if (ret==-1)
   {
       perror("app_serial_baud fail");
     return -1;
   }
   
   //2 设置校验位
   app_serial_stopbit(device,STOP_BIT_ONE);
   //3 设置停止位
   app_serial_parity(device,PARITY_NONE);

   //4 设置原始模式
   app_serial_makeraw(device);

   //5 设置阻塞模式
    app_serial_isblock(device,1);
   //6 flush生效
   tcflush(device->dev_fd,TCIOFLUSH);

    return 0;
}